package com.retch.wenchengmao.sqlitedeme2;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

import com.google.gson.internal.UnsafeAllocator;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * author:wenchengmao
 * time:  2017/3/16.
 * email: wenchengmao@yeah.net
 */

public class MySQLiteHelper<T> extends SQLiteOpenHelper {
    SQLiteDatabase db;

    public MySQLiteHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {

    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

    }


    public void save(Object object) {
        Class<?> table = object.getClass();
        createTableIfNotExits(table);
    }


    //创建数据表
    public void createTableIfNotExits(Class table) {
        if (!tableIsExist(table)) {
            db = getWritableDatabase();
            StringBuilder builder = new StringBuilder();
            builder.append("CREATE TABLE IF NOT EXISTS ");
            builder.append(table.getName().replaceAll("\\.", "_"));
            builder.append(" (");
            Field id = getFieldId(table);
            if (id == null) {
                builder.append("_id Integer PRIMARY KEY,");
            } else {
                builder.append(id.getName()).append(" " + id.getType()).append(" PRIMARY KEY, ");
                Log.d("idName", id.getName() + " type:" + id.getType());
            }
            for (Field field : table.getDeclaredFields()) {
                int modifiers = field.getModifiers();
                if (!field.equals(id) && !Modifier.isStatic(modifiers)) {
                    String s = field.getType().getSimpleName().equals("String") ? "varchar(20)" : field.getType().getSimpleName().equals("int") ? "Integer" : field.getType().getSimpleName().equals("double") ? "real"
                            : field.getType().getSimpleName().equals("float") ? "real": "";
                    builder.append(field.getName()).append(" ").append(s).append(",");
                }
            }
            builder.deleteCharAt(builder.length() - 1);
            builder.append(")");
            Log.d("sqllll", builder.toString());
            db.execSQL(builder.toString());

        }

    }

    //判断数据表是否存在
    public boolean tableIsExist(Class table) {
        boolean result = false;
        if (table == null) {
            return false;
        }
        SQLiteDatabase db = null;
        Cursor cursor = null;
        try {
            db = this.getReadableDatabase();//此this是继承SQLiteOpenHelper类得到的
            String tableName = table.getName().replaceAll("\\.", "_");
            String sql = "select count(*) as c from db_test5 where type ='table' and name ='" +tableName.trim()+"'";
            Log.d("tableNameee", tableName);
            cursor = db.rawQuery(sql, null);
            if (cursor.moveToNext()) {
                int count = cursor.getInt(0);
                if (count > 0) {
                    result = true;
                    Log.d("存在数据表","存在数据表");
                }
            }

        } catch (Exception e) {
            // TODO: handle exception
            Log.d("eeee",e.toString());
        }
        return result;
    }

    /**
     * 获取对象属性中的id字段，如果有就获取，没有就不获取
     *
     * @param table
     * @return
     */
    private Field getFieldId(Class table) {
        Field fieldId = null;
        try {
            fieldId = table.getDeclaredField("id");
            if (fieldId == null) {
                table.getDeclaredField("_id");
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        return fieldId;
    }



    public void clear(Class table) {
        SQLiteDatabase db = getWritableDatabase();
        db.delete(table.getName().replaceAll("\\.","_"), "id>=?", new String[]{String.valueOf(1)});
        Log.d("清空数据表的所有数据","清空数据表的所有数据!");
    }


    public void delete(Object obj,int id) {
        SQLiteDatabase db = getWritableDatabase();
        delete(obj,db,id);
    }

    /**
     * 主要删除操作，主要是通过id来删除，因为删除一条操作必须有一个唯一列项
     * @param obj 指定对象（表）中的数据
     * @param db
     */
    private void delete(Object obj, SQLiteDatabase db,int id){
        //首先获取该类中的id，如果有就会获取到
        Field idField = getFieldId(obj.getClass());
        //如果不存在属性id，就不需要删除
        if (idField != null) {
            idField.setAccessible(true);
        //    idField.getName().replaceAll("\\.","_") + " ="+id,
            try {
                Log.d("field",idField.get(obj).toString());
                db.delete(obj.getClass().getName().replaceAll("\\.", "_"),
                        "id="+id,null);
                Log.d("删除指定数据","删除指定数据!");
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }


    public void deleteAll(Collection collection) {

    }

    public List<T> queryOneData(Class table,int id)
    {
        String tableName = table.getName().replaceAll("\\.", "_");
        db = getReadableDatabase();
        Cursor cursor = db.query(tableName, null, "id=?", new String[]{String.valueOf(id)}, null, null, null);
        String setter=null;
        List<T>list=new ArrayList<>();
        while (cursor.moveToNext()) {
            T object = null;
            try {
                object= (T) table.newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            Field[] declaredFields = object.getClass().getDeclaredFields();
            for (int i =0; i < declaredFields.length; i++) {
                String fieldName = declaredFields[i].getName();
                //getShadow$_monitor_
                if ("shadow$_monitor_".equals(fieldName)||"setSerialVersionUID".equals(fieldName)) {
                    continue;
                }
                String firstLetter = fieldName.substring(0, 1).toUpperCase();
                setter = "set" + firstLetter + fieldName.substring(1);
                Log.e("declaredFieldsType",declaredFields[i].getType().getSimpleName()+"");
                try{
                    if (declaredFields[i].getType().getSimpleName().equals("String")) {
                        Method method = object.getClass().getDeclaredMethod(setter, new Class[] {String.class});
                        method.invoke(object, new Object[]{cursor.getString(i)});
                    } else if (declaredFields[i].getType().getSimpleName().equals("int")) {
                        Method method = object.getClass().getDeclaredMethod(setter, new Class[] {int.class});
                        method.invoke(object, new Object[]{cursor.getInt(i)});
                    } else if(declaredFields[i].getType().getSimpleName().equals("double")){
                        Method method=object.getClass().getDeclaredMethod(setter,new Class[]{double.class});
                        method.invoke(object,new Object[]{cursor.getDouble(i)});
                    } else if(declaredFields[i].getType().getSimpleName().equals("float")){
                        Method method=object.getClass().getDeclaredMethod(setter,new Class[]{float.class});
                        method.invoke(object,new Object[]{cursor.getFloat(i)});
                    }
                }catch (NoSuchMethodException no)
                {
                    no.printStackTrace();
                }
                catch (InvocationTargetException in)
                {
                    in.printStackTrace();
                }catch (IllegalAccessException il)
                {
                    il.printStackTrace();
                }
            }
            list.add(object);

            Log.d("object",object.toString());
        }
        db.close();
        return list;
    }

    public List<T> querySingleData(Class table,String content)
    {
        String tableName = table.getName().replaceAll("\\.", "_");
        db = getReadableDatabase();
        Cursor cursor = db.query(tableName, null, "id=? or name=?", new String[]{content,content}, null, null, null);
        String setter=null;
        List<T>list=new ArrayList<>();
        while (cursor.moveToNext()) {
            T object = null;
            try {
                object= (T) table.newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            Field[] declaredFields = object.getClass().getDeclaredFields();
            for (int i =0; i < declaredFields.length; i++) {
                String fieldName = declaredFields[i].getName();
                //getShadow$_monitor_
                if ("shadow$_monitor_".equals(fieldName)||"setSerialVersionUID".equals(fieldName)) {
                    continue;
                }
                String firstLetter = fieldName.substring(0, 1).toUpperCase();
                setter = "set" + firstLetter + fieldName.substring(1);
                Log.e("declaredFieldsType",declaredFields[i].getType().getSimpleName()+"");
                try{
                    if (declaredFields[i].getType().getSimpleName().equals("String")) {
                        Method method = object.getClass().getDeclaredMethod(setter, new Class[] {String.class});
                        method.invoke(object, new Object[]{cursor.getString(i)});
                    } else if (declaredFields[i].getType().getSimpleName().equals("int")) {
                        Method method = object.getClass().getDeclaredMethod(setter, new Class[] {int.class});
                        method.invoke(object, new Object[]{cursor.getInt(i)});
                    } else if(declaredFields[i].getType().getSimpleName().equals("double")){
                        Method method=object.getClass().getDeclaredMethod(setter,new Class[]{double.class});
                        method.invoke(object,new Object[]{cursor.getDouble(i)});
                    } else if(declaredFields[i].getType().getSimpleName().equals("float")){
                        Method method=object.getClass().getDeclaredMethod(setter,new Class[]{float.class});
                        method.invoke(object,new Object[]{cursor.getFloat(i)});
                    }
                }catch (NoSuchMethodException no)
                {
                    no.printStackTrace();
                }
                catch (InvocationTargetException in)
                {
                    in.printStackTrace();
                }catch (IllegalAccessException il)
                {
                    il.printStackTrace();
                }
            }
            list.add(object);

            Log.d("object",object.toString());
        }
        db.close();
        return list;
    }




    public List<T> queryAllData(Class table)  {
        String tableName = table.getName().replaceAll("\\.", "_");
        db = getReadableDatabase();
        Cursor cursor = db.query(tableName, null, null, null, null, null, null);
        String setter=null;
        List<T>list=new ArrayList<>();
        while (cursor.moveToNext()) {
            T object = null;
            try {
                object= (T) table.newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            Field[] declaredFields = object.getClass().getDeclaredFields();
            for (int i =0; i < declaredFields.length; i++) {
                String fieldName = declaredFields[i].getName();
                //getShadow$_monitor_
                if ("shadow$_monitor_".equals(fieldName)||"setSerialVersionUID".equals(fieldName)) {
                    continue;
                }
                String firstLetter = fieldName.substring(0, 1).toUpperCase();
                setter = "set" + firstLetter + fieldName.substring(1);
                Log.e("declaredFieldsType",declaredFields[i].getType().getSimpleName()+"");
                try{
                    if (declaredFields[i].getType().getSimpleName().equals("String")) {
                        Method method = object.getClass().getDeclaredMethod(setter, new Class[] {String.class});
                        method.invoke(object, new Object[]{cursor.getString(i)});
                    } else if (declaredFields[i].getType().getSimpleName().equals("int")) {
                        Method method = object.getClass().getDeclaredMethod(setter, new Class[] {int.class});
                        method.invoke(object, new Object[]{cursor.getInt(i)});
                    } else if(declaredFields[i].getType().getSimpleName().equals("double")){
                        Method method=object.getClass().getDeclaredMethod(setter,new Class[]{double.class});
                        method.invoke(object,new Object[]{cursor.getDouble(i)});
                    } else if(declaredFields[i].getType().getSimpleName().equals("float")){
                        Method method=object.getClass().getDeclaredMethod(setter,new Class[]{float.class});
                        method.invoke(object,new Object[]{cursor.getFloat(i)});
                    }
                }catch (NoSuchMethodException no)
                {
                    no.printStackTrace();
                }
                catch (InvocationTargetException in)
                {
                    in.printStackTrace();
                }catch (IllegalAccessException il)
                {
                    il.printStackTrace();
                }
            }
            list.add(object);

            Log.d("object",object.toString());
        }

        db.close();
        return list;
    }


    public boolean upDate(Class table, Object object, int id) {
        SQLiteDatabase db=getWritableDatabase();
        boolean result;
        //将一个对象中的所有字段添加到该数据集中
        ContentValues contentValues = new ContentValues();
        //通过反射获取一个类中的所有属性
        Field[] declaredFields = table.getDeclaredFields();
        for(int i=0;i<declaredFields.length;i++)
        {
            int modifiers = declaredFields[i].getModifiers();

            try{
                if (!Modifier.isStatic(modifiers)) {
                    //设置一下数据访问权限为最高级别，也就是public
                    declaredFields[i].setAccessible(true);
                    if(!declaredFields[i].getName().equals("id")&&(i!=0))
                    contentValues.put(declaredFields[i].getName(),declaredFields[i].get(object) + "");
                    Log.d("declaredFieldsss",declaredFields[i].get(object).toString());
                }
            }catch (IllegalAccessException il)
            {
                il.printStackTrace();
            }
        }
        //对于一般的数据操作，我们采用通常是insert来插入数据，但是为了防止同一个对象的数据进行刷新，所以采用直接替换掉
        db.update(table.getName().replaceAll("\\.","_"),contentValues,"id=?",new String[]{String.valueOf(id)});
        result=true;
        return result;
    }


    public void insertMultipleData(List<Object> list) {
        ContentValues contentValues=new ContentValues();
        SQLiteDatabase db=getWritableDatabase();
        for(int i=0;i<list.size();i++)
        {
            Field [] declaredFields=list.get(i).getClass().getDeclaredFields();
            for(int j=0;j<declaredFields.length;j++)
            {
                String fieldName=declaredFields[j].getName();
                String firstLetter = fieldName.substring(0, 1).toUpperCase();
                String getter = "get" + firstLetter + fieldName.substring(1);
                try{
                    Method method = list.get(i).getClass().getMethod(getter, new Class[] {});
                    method.invoke(list.get(i),new Object[]{});
                    //获取对应的修饰类型
                    int modifiers = declaredFields[j].getModifiers();
                    //如果不是静态的就插入到数据库
                    if (!Modifier.isStatic(modifiers)) {
                        //设置一下数据访问权限为最高级别，也就是public
                        declaredFields[j].setAccessible(true);
                        try {
                            //将每一个字段的信息保存到数据集中
                            contentValues.put(declaredFields[j].getName(),declaredFields[j].get(list.get(i)) + "");
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }
                }catch (NoSuchMethodException no)
                {
                    no.printStackTrace();
                }
                catch (InvocationTargetException in)
                {
                    in.printStackTrace();
                }catch (IllegalAccessException il)
                {
                    il.printStackTrace();
                }
            }
            db.replace(list.get(i).getClass().getName().replaceAll("\\.","_"),null,contentValues);
            Log.d("插入多条数据成功!","插入多条数据成功!");

        }


    }


    public void insertSingleDate(Object object) {
        ContentValues contentValues=new ContentValues();
        SQLiteDatabase db=getWritableDatabase();
        Field [] declaredFields=object.getClass().getDeclaredFields();
        for(int j=0;j<declaredFields.length;j++)
        {
            String fieldName=declaredFields[j].getName();
            String firstLetter = fieldName.substring(0, 1).toUpperCase();
            String getter = "get" + firstLetter + fieldName.substring(1);
            try{
                Method method = object.getClass().getMethod(getter, new Class[] {});
                method.invoke(object,new Object[]{});
                //获取对应的修饰类型
                int modifiers = declaredFields[j].getModifiers();
                //如果不是静态的就插入到数据库
                if (!Modifier.isStatic(modifiers)) {
                    //设置一下数据访问权限为最高级别，也就是public
                    declaredFields[j].setAccessible(true);
                    try {
                        //将每一个字段的信息保存到数据集中
                        contentValues.put(declaredFields[j].getName(),declaredFields[j].get(object) + "");
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }catch (NoSuchMethodException no)
            {
                no.printStackTrace();
            }
            catch (InvocationTargetException in)
            {
                in.printStackTrace();
            }catch (IllegalAccessException il)
            {
                il.printStackTrace();
            }
        }
        db.replace(object.getClass().getName().replaceAll("\\.","_"),null,contentValues);
        Log.d("插入单条数据成功!","插入单条数据成功!");
    }

    public void deleteOneData(Class table, int id) {
        SQLiteDatabase db = getWritableDatabase();
        db.delete(table.getName().replaceAll("\\.","_"), "id=?", new String[]{String.valueOf(id)});
        Log.d("删除选中的数据","删除选中的数据!");
    }

    /**
     * 保存数据的主要操作
     *
     * @param obj   数据库对象
     * @param table 对象类类型
     * @param db    操作数据库
     */
    private void insert(Object obj, Class<?> table, SQLiteDatabase db) {
        //将一个对象中的所有字段添加到该数据集中
        ContentValues contentValues = new ContentValues();
        //通过反射获取一个类中的所有属性
        Field[] declaredFields = table.getDeclaredFields();
        //遍历所有的属性
        for (Field field : declaredFields) {
            //获取对应的修饰类型
            int modifiers = field.getModifiers();
            //如果不是静态的就插入到数据库
            if (!Modifier.isStatic(modifiers)) {
                //设置一下数据访问权限为最高级别，也就是public
                field.setAccessible(true);
                try {
                    //将每一个字段的信息保存到数据集中
                    contentValues.put(field.getName(),field.get(obj) + "");
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }

        //对于一般的数据操作，我们采用通常是insert来插入数据，但是为了防止同一个对象的数据进行刷新，所以采用直接替换掉
        db.replace(table.getName().replaceAll("\\.", "_"), null, contentValues);

        Log.d("插入数据表", "插入数据表成功!");
    }


}

